package com.xuecheng.checkcode.domain.service.impl;

import cn.hutool.extra.spring.SpringUtil;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.base.util.EncryptUtil;
import com.xuecheng.checkcode.domain.model.dto.CheckCodeGenerateDto;
import com.xuecheng.checkcode.domain.model.dto.CheckResult;
import com.xuecheng.checkcode.domain.model.enums.CheckResultEnum;
import com.xuecheng.checkcode.domain.model.vo.req.CheckCodeQry;
import com.xuecheng.checkcode.domain.model.vo.req.CheckCodeVerifyQry;
import com.xuecheng.checkcode.domain.model.vo.resp.CheckCodeResp;
import com.xuecheng.checkcode.domain.service.CheckCodeService;
import com.xuecheng.checkcode.domain.template.AbstractCheckCodeTemplate;
import com.xuecheng.checkcode.domain.template.impl.CaffeineCheckCodeTemplate;
import com.xuecheng.checkcode.domain.template.impl.RedisCheckCodeTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: LiJunXi
 * @Description:
 * @Date: 2024-09-07  18:09
 */
@Slf4j
@Service
public class CheckCodeServiceImpl implements CheckCodeService {

    @Autowired
    private DefaultKaptcha kaptcha;

    private static Map<Integer, String> map = new HashMap<>();

    static {
        map.put(1, "redisCheckCodeTemplate");
        map.put(2, "caffeineCheckCodeTemplate");
    }

    @Value("${checkcode.source}")
    public Integer checkCodeSource;

    @Override
    public CheckCodeResp generateCheckCode(CheckCodeQry checkCodeQry) {
        try {
            String classStr = map.get(checkCodeSource);
            AbstractCheckCodeTemplate checkCodeTemplate = SpringUtil.getBean(classStr);
            CheckCodeGenerateDto generate = checkCodeTemplate.generate(4);
            return new CheckCodeResp(generate.getKey(), getPic(generate.getValue()));
        } catch (Exception e) {
            log.error("生成验证码出错，{}", e.getMessage());
            throw new XueChengPlusException("生成验证码出错");
        }
    }

    @Override
    public Boolean verify(CheckCodeVerifyQry checkCodeVerifyQry) {
        String classStr = map.get(checkCodeSource);
        AbstractCheckCodeTemplate checkCodeTemplate = SpringUtil.getBean(classStr);
        CheckResult checkResult = checkCodeTemplate.check(checkCodeVerifyQry.getKey(), checkCodeVerifyQry.getCode());

        // 根据返回类型来判断返回消息
        Boolean flag = checkResult.getFlag();
        if (!flag && CheckResultEnum.ERROR.getType().equals(checkResult.getType())){
            // 失败了记录次数，超过三次就冻结1分钟
            if (checkCodeTemplate.checkErrorTime(checkCodeVerifyQry.getKey())){
                // 达到最大值直接返回
                return false;
            }
        }
        if(flag){
            // 若成功了，就删除验证码
            checkCodeTemplate.deleteKey(checkCodeVerifyQry.getKey());
        }

        return flag;
    }

    /**
     * 生成图片
     * @return
     */
    private String getPic(String code){
        // 生成图片验证码
        ByteArrayOutputStream outputStream = null;
        BufferedImage image = kaptcha.createImage(code);

        outputStream = new ByteArrayOutputStream();
        String imgBase64Encoder = null;
        try {
            // 对字节数组Base64编码
            ImageIO.write(image, "png", outputStream);
            imgBase64Encoder = "data:image/png;base64," + EncryptUtil.encodeBase64(outputStream.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return imgBase64Encoder;
    }


}
